package main

import (
	"encoding/json"
	"fmt"
	"github.com/lxn/walk"
	. "github.com/lxn/walk/declarative"
	"net"
	"os"
	//"strings"
)

var outTE, contentTe *walk.TextEdit
var cbox *walk.ComboBox
var label *walk.Label
var conn net.Conn
var maxRead = 1100
var userName string
var ip, port *walk.LineEdit
var start *walk.PushButton

type Species struct {
	Id   int
	Name string
}

type Msg struct {
	Type       string
	UserName   string
	ToUserName string
	Content    string
	DateTime   string
	List       map[string]int
}

type ClientMsg struct {
	Type       string
	UserName   string
	ToUserName string
	Content    string
}

func KnownSpecies() []*Species {
	return []*Species{}
}

func main() {

	var mw *walk.MainWindow
	var acceptPB, cancelPB *walk.PushButton

	/*	go func() {
		conn = connectServer()
		connectionHandler(conn)
	}()*/

	MainWindow{
		AssignTo: &mw,
		Title:    "golang聊天室client端",
		MinSize:  Size{356, 526},
		Layout:   VBox{},
		Children: []Widget{
			Label{
				Text: "go开发的聊天室v1.1",
			},
			TextEdit{
				AssignTo: &outTE,
				ReadOnly: true,
				Text:     "",
			},
			Composite{
				Layout:  HBox{},
				MaxSize: Size{100, 60},
				Children: []Widget{
					Label{
						Text: "服务ip:",
					},
					LineEdit{
						AssignTo: &ip,
						MaxSize:  Size{130, 60},
						Text:     "10.15.54.16",
					},
					Label{
						Text: "端口:",
					},
					LineEdit{
						AssignTo: &port,
						MaxSize:  Size{56, 60},
						Text:     "61168",
					},
					PushButton{
						AssignTo: &start,
						MaxSize:  Size{16, 60},
						Text:     "登录",
						OnClicked: func() {
							go func() {
								conn = connectServer()
								connectionHandler(conn)
							}()

						},
					},
				},
			},

			Composite{
				Layout: Grid{Columns: 2},
				Children: []Widget{
					Label{
						Text: "当前用户:",
					},
					Label{
						AssignTo: &label,
						Text:     "",
					},
					Label{
						Text: "在线列表:",
					},
					ComboBox{
						AssignTo:      &cbox,
						Value:         Bind("SpeciesId", SelRequired{}),
						BindingMember: "Id",
						DisplayMember: "Name",
						Model:         KnownSpecies(),
						OnCurrentIndexChanged: func() {
							//fmt.Println("change ", cbox.Text())
						},
					},
				},
			},

			TextEdit{
				AssignTo: &contentTe,
				MaxSize:  Size{60, 50},
				Text:     "",
			},

			Composite{
				Layout: HBox{},
				Children: []Widget{
					HSpacer{},
					PushButton{
						AssignTo: &acceptPB,
						Text:     "发送",
						OnClicked: func() {
							//fmt.Println("select:", cbox.Text())
							go sendMsg(&ClientMsg{"msg", "", cbox.Text(), contentTe.Text()})
						},
					},
					PushButton{
						AssignTo: &cancelPB,
						Text:     "关闭",
						OnClicked: func() {
							os.Exit(0)
						},
					},
				},
			},
		},
	}.Run()

}

func console(str string) {
	if outTE != nil {
		str += "\r\n"
		outTE.AppendText(str)
	}

}

func showMsg(msg string) {
	//fmt.Println(msg)
	defer func() {
		if err := recover(); err != nil {
			fmt.Println("go to defer")
			fmt.Println(err) // 这里的err其实就是panic传入的内容，55
		}
	}()
	var m Msg
	err := json.Unmarshal([]byte(msg), &m)
	if err != nil {
		fmt.Println("showMsg Error %s", err.Error())
	} else {
		for {
			if outTE != nil {
				str := "\r\n"
				if m.Type == "msg" {
					str += "[" + m.UserName + "] " + m.DateTime + "\r\n"
					str += m.Content + "\r\n"
					outTE.AppendText(str)
				} else if m.Type == "msgTo" {
					if m.UserName == userName {
						str += "你对[" + m.ToUserName + "]说:" + m.DateTime + "\r\n"
					} else {
						str += "[" + m.UserName + "] 对你说:" + m.DateTime + "\r\n"
					}
					str += m.Content + "\r\n"
					outTE.AppendText(str)
				} else if m.Type == "join" {
					str += "欢迎" + "[" + m.UserName + "] 进入系统 " + m.DateTime + "\r\n"
					outTE.AppendText(str)
				} else if m.Type == "list" {
					go updateUserList(m.List)

				} else if m.Type == "out" {
					str += "[" + m.UserName + "] 离开了系统 " + m.DateTime + "\r\n"
					outTE.AppendText(str)
				} else if m.Type == "err" {
					str += "[system] " + m.DateTime + "\r\n"
					str += "错误提示:" + m.Content + "\r\n"
					outTE.AppendText(str)
				} else if m.Type == "ip" {
					go func() {
						for {
							if label != nil {
								userName = m.UserName
								label.SetText(m.UserName)
								break
							}
						}
					}()
				}
				break
			}
		}

	}
}

func updateUserList(list map[string]int) {
	for {
		if cbox != nil {
			sdata := make([]*Species, 0)
			i := 2
			sdata = append(sdata, &Species{1, "---所有人---"})
			for key, _ := range list {
				if key == userName {
					continue
				}
				tmp := &Species{}
				tmp.Id = i
				tmp.Name = key
				sdata = append(sdata, tmp)
				i++
			}
			errz := cbox.SetModel(func() []*Species {
				//fmt.Println("debug11:", sdata)
				return sdata
			}())
			if errz != nil {
				fmt.Println("updateUserList err ", errz.Error())
			}
			cbox.SetCurrentIndex(0)
			break
		}
	}

}

func connectServer() net.Conn {
	var conn net.Conn
	var error error
	ipText := ip.Text()
	portText := port.Text()
	if ipText != "" && portText != "" {
		conn, error = net.Dial("tcp", ipText+":"+portText)
		fmt.Println("start to connect server")
		checkError(error)
	}
	return conn
}

func sendMsg(msg *ClientMsg) {
	ulistStr, err := json.Marshal(msg)
	if err != nil {
		fmt.Println("sendMsg josn Error %s", err.Error())
	} else {
		_, error := conn.Write([]byte(ulistStr))
		checkError(error)
	}
}

func checkError(error error) {
	if error != nil {
		console(error.Error())
		fmt.Println("Error: " + error.Error()) // terminate program
	}
}

func connectionHandler(conn net.Conn) {
	if conn == nil {
		return
	}
	start.SetVisible(false)
	for {
		var ibuf []byte = make([]byte, 1024)
		length, err := conn.Read(ibuf)
		fmt.Println("length is ", length)
		//ibuf[maxRead] = 0
		if err == nil {
			handleMsg(length, err, ibuf)
		} else {
			break
		}
	}
}

func handleMsg(length int, err error, msg []byte) {
	if length > 0 {
		for i := 0; i < length; i++ {
			if i > 0 && msg[i] == '{' && msg[i-1] != ':' {
				showMsg(string(msg[0:i]))
				handleMsg(length-i, err, msg[i:length])
				return
			}
		}
		showMsg(string(msg[0:length]))
	}

}
